\chapter{Tenon tbin文件的执行}

由Compiler类生成的tbin文件可以作为一个Task由Executor类执行。
每个Executor类里基本的执行单元是Task类。每个Executor可以包含多个Task.

每个tbin文件的执行实例由一个Task表示。每个Task在一个线程中执行。Task执行前需要指定入口函数。
Task可以执行的代码包括这个tbin文件里所有的模块，以及此Task导入的其它库里的所有的模块。
一个Task无法执行多个tbin文件。

\section{执行示例}

下面的例子代码在一个Executor中使用一个Task执行mytask.tbin文件的代码，入口函数为"main".

\begin{verbatim}
tlang::Executor executor;
executor.addExtFunctions("myinstructions", MyExtFuncs);

auto task = executor.addTask();
task->setBin("/path/to/mytask.tbin");
task->setEntry("main");

executor.execute();
executor.removeTask(task);
\end{verbatim}

\section{Executor类}

Executor类作为Tenon代码执行的总接口。每个Executor类可以执行多个Task.

在使用时，Executor可以作为一个常驻对象，将扩展函数注册进去，不必频繁创建释放。

\subsection{Executor::addTask}

在Executor中创建一个Task.

在使用时，Task作为一个按需创建的对象，运行完就通过Executor::removeTask释放掉。下次有任务运行再创建新的Task.

\subsection{Executor::addExtFunctions}

为Executor注册扩展函数。

\subsection{Executor::execute}

启动执行Executor中所有的Task.

\subsection{Exeuctor::removeTask}

移除Executor中的Task.

\section{Task类}

Task是Tenon代码执行的载体。每个Task执行一个tbin文件。每个Task在一个单独的线程中执行。

\subsection{Task::setBin}

为Task设置要执行的tbin文件。

\subsection{Task::setEntry}

为Task设置要执行tbin文件的入口函数。入口函数不能有参数和返回值。

\section{PrintClient类}

可以为每个Task设定一个PrintClient类的实例，在该Task运行的过程中，print/TPWrite函数在进行打印操作时，
会调用此实例的output函数进行实际的打印操作。另外，Task运行过程中产生的错误信息，
也会通过调用此实例的error函数进行实际的错误信息打印操作。

PrintClient类的声明如下：

\begin{verbatim}

namespace tlang {

class PrintClient {
public:
    virtual ~PrintClient() {}

    virtual void output(std::string_view str) {}
    virtual void output(const char* fmt, ...) {}
    virtual void error(std::string_view str) {}
    virtual void error(const char* fmt, ...) {}
    virtual void flush() {}
};

}

\end{verbatim}

可以通过Executor类的setPrintClient方法设置一个Task的PrintClient实例。

\section{DatabaseInstance类}

可以通过Executor类的setDatabase方法设置一个DatabaseInstance类的实例，供所有的Task使用。Task中pers数据类型功能的实现就是通过调用该实例的loadPers/storePers接口完成的。

DatabaseInstance类的声明如下：

\begin{verbatim}

namespace tlang {

class DatabaseInstance {
protected:
    PrintClient* client;

public:
    DatabaseInstance() : client{nullptr} {}
    virtual ~DatabaseInstance() {}
    void setPrintClient(PrintClient* c) { client = c; }
    virtual void loadPers(Task*, Module*, Var*) {}
    virtual void storePers(Task*, Module*, Var*) {}
};

}

\end{verbatim}
